package org.openarchitectureware.recipe2.findbugs;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;

import org.openarchitectureware.recipe2.findbugs.impl.PredefInstanceImpl;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;
import org.xml.sax.EntityResolver;
import org.xml.sax.SAXException;

public class XMLPredefInstancesReader {

	private static DocumentBuilder docBuilder;

	public static DocumentBuilder getDocBuilder(EntityResolver entityResolver) {
		if (docBuilder == null) {
			try {
				DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
				factory.setValidating(false);
				docBuilder = factory.newDocumentBuilder();
				if (entityResolver != null) {
					docBuilder.setEntityResolver(entityResolver);
				}
			} catch (ParserConfigurationException e) {
				throw new RuntimeException(e);
			}
		}
		return docBuilder;
	}

	public static List<PredefInstance> getPredefInstances(String predefName, Object context) throws IOException {
		List<PredefInstance> instances = new ArrayList<PredefInstance>();
		for (PredefInstance i : loadPredefInstances(context)) {
			if (i.getPredef().equals(predefName)) {
				instances.add(i);
			}
		}
		return instances;
	}
	
	public static Document loadDocument(File file) throws SAXException, IOException {
		Document document = getDocBuilder(null).parse(file);
		return document;
	}

	public static Document loadDocument(InputStream in) throws SAXException, IOException {
		Document document = getDocBuilder(null).parse(in);
		return document;
	}

	private static List<PredefInstance> loadPredefInstances(InputStream in) throws IOException {
		List<PredefInstance> instances = new ArrayList<PredefInstance>();
		try {
			Document document = loadDocument(in);
			NodeList instanceNodes = document.getDocumentElement().getElementsByTagName("predef-instance");
			for (int i = 0; i < instanceNodes.getLength(); ++i) {
				Element instanceNode = (Element) instanceNodes.item(i);
				PredefInstanceImpl instance = new PredefInstanceImpl();
				NodeList messageElements = instanceNode.getElementsByTagName("message");
				String message = null;
				if (messageElements.getLength() > 0) {
					message = messageElements.item(0).getTextContent();
				}
				if (message != null) {
					instance.setMessage(message);
				}
				String predef = instanceNode.getAttribute("predef");
				instance.setPredef(predef);
				NodeList paramNodes = instanceNode.getElementsByTagName("param");
				for (int p = 0; p < paramNodes.getLength(); ++p) {
					Element param = (Element) paramNodes.item(p);
					instance.addParameter(param.getAttribute("name"), param.getAttribute("value"));
				}
				instances.add(instance);
			}
		} catch (SAXException e) {
			IOException ioe = new IOException("SAXException reading predef instances xml file");
			ioe.initCause(e);
			throw ioe;
		}
		return instances;
	}

	private static List<PredefInstance> loadPredefInstances(Object context) throws IOException {
		Class contextClass = null;
		if (context instanceof Class) {
			contextClass = (Class) context;
		} else {
			contextClass = context.getClass();
		}
		InputStream in = contextClass.getClassLoader().getResourceAsStream("predef-instances.xml");
		if (in == null) {
			throw new IOException("No predef-instances.xml file found");
		}
		return loadPredefInstances(in);		
	}

}
